import { INode, ILinedList } from "./ILinedList";

export class Node<T> implements Node<T> {
  data: T;
  next: INode<T> | null;
  constructor(data: T) {
    this.data = data;
    this.next = null;
  }
}

export class LinedList<T> implements ILinedList<T> {
  head: INode<T> | null;
  private size: number;
  constructor() {
    this.head = null;
    this.size = 0;
  }
  private getNode(position: number): INode<T> | undefined {
    if (position < 0 || this.size <= position) {
      return undefined;
    }
    let current = this.head!;
    let index = 0;
    while (index < position) {
      current = current.next!;
      index++;
    }
    return current;
  }
  append(item: T): void {
    let newNode = new Node(item);
    if (!this.head) {
      this.head = newNode;
    } else {
      let current = this.head;
      while (current.next) {
        current = current.next;
      }
      current.next = newNode;
    }
    this.size++;
  }
  traverse(): string {
    let values: T[] = [];
    let current = this.head;
    while (current) {
      values.push(current.data);
      current = current.next;
    }
    return values.join("->");
  }
  insert(position: number, element: T): T | null {
    if (!this.size) return null;
    if (position < 0 && position > this.size) {
      return null;
    }
    const newNode = new Node(element);

    if (position === 0) {
      newNode.next = this.head;
      this.head = newNode;
    } else {
      const node = this.getNode(position - 1);
      if (node === undefined) return null;
      newNode.next = node.next;
      node.next = newNode;
    }

    this.size++;
    return newNode.data;
  }
  update(position: number, element: T): boolean {
    const node = this.getNode(position);
    if (node === undefined) return false;
    node.data = element;
    return true;
  }
  removeAt(position: number): T | undefined {
    if (!this.size) return undefined;
    if (position < 0 && position > this.size) return undefined;
    let current = this.head;
    if (position === 0) {
      this.head = current!.next ?? null;
    } else {
      const preNode = this.getNode(position - 1);
      if (preNode === undefined) return undefined;
      current = preNode.next!;
      preNode.next = preNode.next?.next || null;
    }

    this.size--;
    return current!.data;
  }
  get(position: number): T | undefined {
    return this.getNode(position)?.data;
  }
  isEmpty(): boolean {
    return this.size === 0;
  }

  indexOf(element: T) {
    let current = this.head;
    let idx = 0;
    while (current) {
      if (current.data === element) {
        return idx;
      }
      current = current.next;
      idx++;
    }
    return -1
  }
}

const linedList1 = new LinedList<string>();

linedList1.append("a");
linedList1.append("b");
linedList1.append("c");
linedList1.append("d");
console.log(linedList1.traverse());

// console.log(linedList1.get(0));
// console.log(linedList1.get(1));
// console.log(linedList1.get(2));
// console.log(linedList1.get(3));

// linedList1.insert(2, "嘻");
// console.log(linedList1.traverse());

// linedList1.update(2, "哈");
// console.log(linedList1.traverse());

// console.log(linedList1.removeAt(2));

// console.log(linedList1.traverse());

console.log(linedList1.indexOf("a"));
console.log(linedList1.indexOf("b"));
console.log(linedList1.indexOf("d1"));

